// Test for smem

#include <gtest/gtest.h>
#include "smem.h"


const int HEAP_SIZE = 256;


class SMemTest : public testing::Test {
protected:
	virtual void SetUp() {
		s_self = this;

		smem_init(buf, sizeof(buf), gc);
		nrefered = 0;
	}

	virtual void TearDown() {
		s_self = NULL;
	}

	void add_refered(void* ptr) {
		if (nrefered < MAX_REFERED) {
			refered_ptr[nrefered++] = ptr;
		}
	}

	void remove_refered(void* ptr) {
		for (int i=0; i<nrefered; ++i) {
			if (refered_ptr[i] == ptr) {
				refered_ptr[i] = NULL;
			}
		}
	}

protected:
	void mark() {
		for (int i=0; i<nrefered; ++i) {
			void* ptr = refered_ptr[i];
			if (ptr != NULL) {
				smark_ptr(ptr);
			}
		}
	}

	void gcimpl() {
		mark();
		ssweep();
	}

	unsigned long buf[HEAP_SIZE / sizeof(unsigned long)];

	enum { MAX_REFERED = 16 };
	void* refered_ptr[MAX_REFERED];
	int nrefered;

	static SMemTest* s_self;
	static void gc() {
		s_self->gcimpl();
	}
};

SMemTest* SMemTest::s_self;


//=============================================================================

TEST_F(SMemTest, Allocate) {
	void* ptr1 = smalloc(1);
	EXPECT_NE(ptr1, (void*)NULL) << "Can allocate";

	void* ptr2 = smalloc(0);
	EXPECT_NE(ptr2, (void*)NULL) << "Can allocate 0 byte";
}

TEST_F(SMemTest, CollectGarbage) {
	const char str[] = "This is a test string.";
	char* ptr = (char*)smalloc(strlen(str) + 1);
	strcpy(ptr, str);
	add_refered(ptr);

	gc();

	EXPECT_TRUE(strcmp(ptr, str) == 0) << "refered ptr has alive after occur gc";

	// ptr is exist
}
